Add bare-user-only repo mode
authorAlexander Larsson <alexl@redhat.com>
Wed, 22 Mar 2017 10:59:18 +0000 (11:59 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Mon, 27 Mar 2017 13:48:41 +0000 (13:48 +0000)
This mode is similar to bare-user, but does not store the permission,
ownership (uid/gid) and xattrs in an xattr on the file objects in the
repo. Additionally it stores symlinks as symlinks rather than as
regular files+xattrs, like the bare mode. The later is needed because
we can't store the is-symlink in the xattr.

This means that some metadata is lost, such as the uid. When reading a
repo like this we always report uid, gid as 0, and no xattrs, so
unless this is true in the commit the resulting repository will
not fsck correctly.

However, it the main usecase of the repository is to check out with
--user-mode, then no information is lost, and the repository can
work on filesystems without xattrs (such as tmpfs).

Closes: #750
Approved by: cgwalters

src/libostree/ostree-core-private.h
src/libostree/ostree-core.h
src/libostree/ostree-repo-checkout.c
src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo.c

index fbd9490e0573eba3f30531700dd7a8416b4495c5..a66a068f79c2c744d4e61af747e4494bc765dbf9 100644 (file)
@@ -144,7 +144,8 @@ _ostree_repo_mode_is_bare (OstreeRepoMode mode)
 {
   return
     mode == OSTREE_REPO_MODE_BARE ||
-    mode == OSTREE_REPO_MODE_BARE_USER;
+    mode == OSTREE_REPO_MODE_BARE_USER ||
+    mode == OSTREE_REPO_MODE_BARE_USER_ONLY;
 }
 
 GVariant *
index bcade9db8405395fd14af66b36b8185d9aa10932..b25112db7518c56963a3064e159e57c8e654a54a 100644 (file)
@@ -179,6 +179,7 @@ typedef enum {
  * @OSTREE_REPO_MODE_BARE: Files are stored as themselves; checkouts are hardlinks; can only be written as root
  * @OSTREE_REPO_MODE_ARCHIVE_Z2: Files are compressed, should be owned by non-root.  Can be served via HTTP
  * @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.
+ * @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs.
  *
  * See the documentation of #OstreeRepo for more information about the
  * possible modes.
@@ -186,7 +187,8 @@ typedef enum {
 typedef enum {
   OSTREE_REPO_MODE_BARE,
   OSTREE_REPO_MODE_ARCHIVE_Z2,
-  OSTREE_REPO_MODE_BARE_USER
+  OSTREE_REPO_MODE_BARE_USER,
+  OSTREE_REPO_MODE_BARE_USER_ONLY,
 } OstreeRepoMode;
 
 _OSTREE_PUBLIC
index 5611e6e940208ef72689785b36ae68a956fe1300..09966a94fd274c56961ed1ec9a9b900ed87f80c6 100644 (file)
@@ -473,7 +473,9 @@ checkout_one_file_at (OstreeRepo                        *repo,
                               (current_repo->mode == OSTREE_REPO_MODE_BARE_USER
                                && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER
                                /* NOTE: bare-user symlinks are not stored as symlinks */
-                               && !is_symlink));
+                               && !is_symlink) ||
+                              (current_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY
+                               && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER));
           gboolean current_can_cache = (options->enable_uncompressed_cache
                                         && current_repo->enable_uncompressed_cache);
           gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
@@ -862,6 +864,9 @@ ostree_repo_checkout_tree (OstreeRepo               *self,
 {
   OstreeRepoCheckoutAtOptions options = { 0, };
 
+  if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY)
+    mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+
   options.mode = mode;
   options.overwrite_mode = overwrite_mode;
   /* Backwards compatibility */
@@ -948,6 +953,7 @@ ostree_repo_checkout_at (OstreeRepo                        *self,
                          GError                           **error)
 {
   OstreeRepoCheckoutAtOptions default_options = { 0, };
+  OstreeRepoCheckoutAtOptions real_options;
 
   if (!options)
     {
@@ -955,6 +961,13 @@ ostree_repo_checkout_at (OstreeRepo                        *self,
       options = &default_options;
     }
 
+  /* Make a copy so we can modify the options */
+  real_options = *options;
+  options = &real_options;
+
+  if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY)
+    options->mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+
   g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error);
   if (!commit_root)
     return FALSE;
index 1308ef5cf99f4c60091625cee654decbcee4d109..80c35f4493f604971e41bd1f2b19fab9a0d5b9af 100644 (file)
@@ -227,7 +227,11 @@ commit_loose_object_trusted (OstreeRepo        *self,
     }
 
   /* Special handling for symlinks in bare repositories */
-  if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE)
+  if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
+    {
+      /* We don't store the metadata in bare-user-only, so we're done. */
+    }
+  else if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE)
     {
       /* Now that we know the checksum is valid, apply uid/gid, mode bits,
        * and extended attributes.
@@ -283,7 +287,8 @@ commit_loose_object_trusted (OstreeRepo        *self,
             }
         }
 
-      if (objtype == OSTREE_OBJECT_TYPE_FILE && self->mode == OSTREE_REPO_MODE_BARE_USER)
+      if (objtype == OSTREE_OBJECT_TYPE_FILE &&
+          (self->mode == OSTREE_REPO_MODE_BARE_USER || self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY))
         {
           if (!object_is_symlink)
             {
@@ -302,7 +307,8 @@ commit_loose_object_trusted (OstreeRepo        *self,
                 }
             }
 
-          if (!write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error))
+          if (self->mode == OSTREE_REPO_MODE_BARE_USER &&
+              !write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error))
             goto out;
         }
 
@@ -708,8 +714,10 @@ write_object (OstreeRepo         *self,
                                                              cancellable, error))
             goto out;
         }
-      else if (repo_mode == OSTREE_REPO_MODE_BARE && temp_file_is_symlink)
+      else if (_ostree_repo_mode_is_bare (repo_mode) && temp_file_is_symlink)
         {
+          /* Note: This will not be hit for bare-user mode because its converted to a
+             regular file and take the branch above */
           if (!_ostree_make_temporary_symlink_at (self->tmp_dir_fd,
                                                   g_file_info_get_symlink_target (file_info),
                                                   &temp_filename,
@@ -959,6 +967,7 @@ scan_one_loose_devino (OstreeRepo                     *self,
             case OSTREE_REPO_MODE_ARCHIVE_Z2:
             case OSTREE_REPO_MODE_BARE:
             case OSTREE_REPO_MODE_BARE_USER:
+            case OSTREE_REPO_MODE_BARE_USER_ONLY:
               skip = !g_str_has_suffix (name, ".file");
               break;
             default:
index adc74c0e84149686e792665c48804b1d4fa6b498..5e0a93ec701f3e65a9dcf29b8a6b689a94bbd8af 100644 (file)
@@ -1754,6 +1754,9 @@ ostree_repo_mode_to_string (OstreeRepoMode   mode,
     case OSTREE_REPO_MODE_BARE_USER:
       ret_mode = "bare-user";
       break;
+    case OSTREE_REPO_MODE_BARE_USER_ONLY:
+      ret_mode = "bare-user-only";
+      break;
     case OSTREE_REPO_MODE_ARCHIVE_Z2:
       ret_mode ="archive-z2";
       break;
@@ -1781,6 +1784,8 @@ ostree_repo_mode_from_string (const char      *mode,
     ret_mode = OSTREE_REPO_MODE_BARE;
   else if (strcmp (mode, "bare-user") == 0)
     ret_mode = OSTREE_REPO_MODE_BARE_USER;
+  else if (strcmp (mode, "bare-user-only") == 0)
+    ret_mode = OSTREE_REPO_MODE_BARE_USER_ONLY;
   else if (strcmp (mode, "archive-z2") == 0 ||
            strcmp (mode, "archive") == 0)
     ret_mode = OSTREE_REPO_MODE_ARCHIVE_Z2;
@@ -2907,6 +2912,37 @@ ostree_repo_load_file (OstreeRepo         *self,
                   g_file_info_set_symlink_target (ret_file_info, targetbuf);
                 }
             }
+          else if (repo_mode == OSTREE_REPO_MODE_BARE_USER_ONLY)
+            {
+              glnx_fd_close int fd = -1;
+
+              /* Canonical info is: uid/gid is 0 and no xattrs, which
+                 might be wrong and thus not validate correctly, but
+                 at least we report something consistent. */
+              g_file_info_set_attribute_uint32 (ret_file_info, "unix::uid", 0);
+              g_file_info_set_attribute_uint32 (ret_file_info, "unix::gid", 0);
+
+              if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR &&
+                  out_input)
+                {
+                  fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC);
+                  if (fd < 0)
+                    {
+                      glnx_set_error_from_errno (error);
+                      goto out;
+                    }
+
+                  ret_input = g_unix_input_stream_new (fd, TRUE);
+                  fd = -1; /* Transfer ownership */
+                }
+
+              if (out_xattrs)
+                {
+                  GVariantBuilder builder;
+                  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
+                  ret_xattrs = g_variant_ref_sink (g_variant_builder_end (&builder));
+                }
+            }
           else
             {
               g_assert (repo_mode == OSTREE_REPO_MODE_BARE);